package com.xyc.javase.utils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class DateUtil {

    /**
     * 判断是否为正确的年月  19或20开头的年
     *
     * @param date
     * @return eg. 199910
     */
    public static boolean isyyyyMM(String date) {
        String regex = "^((19|20)[0-9]{2})((0[1-9])|(1[0-2]))$";
        //开始判断,且符合正则表达式
        if (date.matches(regex)) {
            return true;
        }
        return false;
    }

    /**
     * 获取DateFormat
     *
     * @param dateFormat dateFormat = 1 -- yyyyMMdd
     *                   dateFormat = 2 -- yyyy-MM-dd
     *                   dateFormat = 3 -- yyyy/MM/dd
     *                   dateFormat = 4 -- yyyy年MM月dd日
     */
    public static DateFormat dateFormat(int dateFormat) {
        switch (dateFormat) {
            case 1:
                return new SimpleDateFormat("yyyyMMdd");
            case 2:
                return new SimpleDateFormat("yyyy-MM-dd");
            case 3:
                return new SimpleDateFormat("yyyy/MM/dd");
            case 4:
                return new SimpleDateFormat("yyyy年MM月dd日");
            case 5:
            	return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            default:
                return new SimpleDateFormat("yyyyMMdd");
        }
    }

    /**
     * 获取DateFormat
     *
     * @param dateFormat dateFormat = 1 -- yyyyMMddHHmmss
     *                   dateFormat = 2 -- yyyy-MM-dd HH:mm:ss
     *                   dateFormat = 3 -- yyyy/MM/dd HH:mm:ss
     *                   dateFormat = 4 -- yyyy年MM月dd日 HH时mm分ss秒
     */
    public static DateFormat dateTimeFormat(int dateFormat) {
        switch (dateFormat) {
            case 1:
                return new SimpleDateFormat("yyyyMMddHHmmss");
            case 2:
                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            case 3:
                return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
            case 4:
                return new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
            default:
                return new SimpleDateFormat("yyyyMMddHHmmss");
        }
    }

    /**
     * 获取DateFormat
     *
     * @param dateFormat dateFormat = 1 -- HHmmss
     *                   dateFormat = 2 -- HH:mm:ss
     *                   dateFormat = 3 -- HH:mm:ss
     *                   dateFormat = 4 -- HH时mm分ss秒
     */
    public static DateFormat timeFormat(int dateFormat) {
        switch (dateFormat) {
            case 1:
                return new SimpleDateFormat("HHmmss");
            case 2:
                return new SimpleDateFormat("HH:mm:ss");
            case 3:
                return new SimpleDateFormat("HH:mm:ss");
            case 4:
                return new SimpleDateFormat("HH时mm分ss秒");
            default:
                return new SimpleDateFormat("HHmmss");
        }
    }

    /**
     * 获得UTC时间
     * @return
     */
    public static Date getUTCDate(){
        // 取得本地时间
        Calendar cal = Calendar.getInstance();
        // 取得时间偏移量
        int zoneOffset = cal.get(Calendar.ZONE_OFFSET);
        // 取得夏令时差
        int dstOffset = cal.get(Calendar.DST_OFFSET);
        // 从本地时间里扣除这些差量，即可以取得UTC时间
        cal.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        return cal.getTime();
    }

    /**
     * 获取当前日期字符串
     *
     * @param dateFormat dateFormat = 1 -- yyyyMMdd
     *                   dateFormat = 2 -- yyyy-MM-dd
     *                   dateFormat = 3 -- yyyy/MM/dd
     *                   dateFormat = 4 -- yyyy年MM月dd日
     * @return
     */
    public static String getCurrDateStr(int dateFormat) {
        return dateFormat(dateFormat).format(new Date());
    }

    /**
     * 获取当前日期 yyyy-MM-dd 00:00:00
     *
     * @return
     */
    public static Date getCurrDate() {
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.clear(Calendar.MILLISECOND);
        c.clear(Calendar.SECOND);
        c.clear(Calendar.MINUTE);
        c.clear(Calendar.HOUR_OF_DAY);
        c.clear(Calendar.HOUR);
        c.clear(Calendar.AM_PM);
        return c.getTime();
    }

    /**
     * 格式化日期
     *
     * @param date
     * @param dateFormat dateFormat = 1 -- yyyyMMdd
     *                   dateFormat = 2 -- yyyy-MM-dd
     *                   dateFormat = 3 -- yyyy/MM/dd
     *                   dateFormat = 4 -- yyyy年MM月dd日
     *                   dateFormat = 5 -- yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static String date2string(Date date, int dateFormat) {
        return dateFormat(dateFormat).format(date);
    }

    /**
     * 格式化日期字符串
     *
     * @param date
     * @param dateFormat dateFormat = 1 -- yyyyMMdd
     *                   dateFormat = 2 -- yyyy-MM-dd
     *                   dateFormat = 3 -- yyyy/MM/dd
     *                   dateFormat = 4 -- yyyy年MM月dd日
     * @return
     */
    public static Date string2date(String date, int dateFormat) throws ParseException {
        return dateFormat(dateFormat).parse(date);
    }

    /**
     * 日期比较
     *
     * @param time1      起始日期
     * @param time2      结束日期
     * @param dateFormat dateFormat = 1 -- yyyyMMdd
     *                   dateFormat = 2 -- yyyy-MM-dd
     *                   dateFormat = 3 -- yyyy/MM/dd
     *                   dateFormat = 4 -- yyyy年MM月dd日
     * @throws ParseException
     * @return 起始日期小于结束日期返回true，否则返回false
     */
    public static boolean isBeforeDate(String time1, String time2, int dateFormat) throws ParseException {
        Date date1 = dateFormat(dateFormat).parse(time1);
        Date date2 = dateFormat(dateFormat).parse(time2);
        return date1.before(date2);
    }

    /**
     * 获取指定日期之前或之后多少天的时间字符串
     *
     * @param date       待加、减天数
     * @param day        加、减天数
     * @return
     */
    public static Date rollDay(Date date, int day) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_MONTH, day);
        return c.getTime();
    }

    /**
     * 获取指定日期之前或之后多少天的时间字符串
     *
     * @param date       待加、减天数
     * @param day        加、减天数
     * @param dateFormat dateFormat = 1 -- yyyyMMdd
     *                   dateFormat = 2 -- yyyy-MM-dd
     *                   dateFormat = 3 -- yyyy/MM/dd
     *                   dateFormat = 4 -- yyyy年MM月dd日
     * @return
     */
    public static String rollDay(Date date, int day, int dateFormat) {
        Date d = rollDay(date, day);
        return dateFormat(dateFormat).format(d);
    }

    /**
     * 获取指定日期之前或之后多少个月的时间字符串
     *
     * @param date       待加、减月数
     * @param month        加、减月数
     * @return
     */
    public static Date rollMonth(Date date, int month) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.MONTH, month);
        return c.getTime();
    }

    /**
     * 获取指定日期之前或之后多少个月的时间字符串
     *
     * @param date       待加、减月数
     * @param month        加、减月数
     * @param dateFormat dateFormat = 1 -- yyyyMMdd
     *                   dateFormat = 2 -- yyyy-MM-dd
     *                   dateFormat = 3 -- yyyy/MM/dd
     *                   dateFormat = 4 -- yyyy年MM月dd日
     * @return
     */
    public static String rollMonth(Date date, int month, int dateFormat) {
        Date d = rollMonth(date, month);
        return dateFormat(dateFormat).format(d);
    }

    /**
     * 获取当前时间字符串
     *
     * @param dateFormat dateFormat = 1 -- yyyyMMddHHmmss
     *                   dateFormat = 2 -- yyyy-MM-dd HH:mm:ss
     *                   dateFormat = 3 -- yyyy/MM/dd HH:mm:ss
     *                   dateFormat = 4 -- yyyy年MM月dd日 HH时mm分ss秒
     * @return
     */
    public static String getCurrDateTimeStr(int dateFormat) {
        return dateTimeFormat(dateFormat).format(new Date());
    }

    /**
     * 格式化时间字符串
     *
     * @param dateTime
     * @param dateFormat dateFormat = 1 -- yyyyMMddHHmmss
     *                   dateFormat = 2 -- yyyy-MM-dd HH:mm:ss
     *                   dateFormat = 3 -- yyyy/MM/dd HH:mm:ss
     *                   dateFormat = 4 -- yyyy年MM月dd日 HH时mm分ss秒
     * @return
     */
    public static Date string2datetime(String dateTime, int dateFormat) throws ParseException {
        return dateTimeFormat(dateFormat).parse(dateTime);
    }

    /**
     * 格式化时间
     *
     * @param dateTime
     * @param dateFormat dateFormat = 1 -- yyyyMMddHHmmss
     *                   dateFormat = 2 -- yyyy-MM-dd HH:mm:ss
     *                   dateFormat = 3 -- yyyy/MM/dd HH:mm:ss
     *                   dateFormat = 4 -- yyyy年MM月dd日 HH时mm分ss秒
     * @return
     */
    public static String datetime2string(Date dateTime, int dateFormat) {
        return dateTimeFormat(dateFormat).format(dateTime);
    }

    /**
     * 格式化时间
     *
     * @param time
     * @param dateFormat dateFormat = 1 -- HHmmss
     *                   dateFormat = 2 -- HH:mm:ss
     *                   dateFormat = 3 -- HH:mm:ss
     *                   dateFormat = 4 -- HH时mm分ss秒
     * @return
     */
    public static String time2string(Date time, int dateFormat) {
        return timeFormat(dateFormat).format(time);
    }

    /**
     * 时间比较
     *
     * @param time1      起始时间
     * @param time2      结束时间
     * @param dateFormat dateFormat = 1 -- yyyyMMddHHmmss
     *                   dateFormat = 2 -- yyyy-MM-dd HH:mm:ss
     *                   dateFormat = 3 -- yyyy/MM/dd HH:mm:ss
     *                   dateFormat = 4 -- yyyy年MM月dd日 HH时mm分ss秒
     * @throws ParseException
     * @return 起始时间小于结束时间返回true，否则返回false
     */
    public static boolean isBeforeDateTime(String time1, String time2, int dateFormat) throws ParseException {
        Date date1 = dateTimeFormat(dateFormat).parse(time1);
        Date date2 = dateTimeFormat(dateFormat).parse(time2);
        return date1.before(date2);
    }

    /**
     * 获取指定时间之前或之后多少秒的时间字符串
     *
     * @param dateTime   待加、减时间
     * @param sec        加、减秒数
     * @param dateFormat dateFormat = 1 -- yyyyMMddHHmmss
     *                   dateFormat = 2 -- yyyy-MM-dd HH:mm:ss
     *                   dateFormat = 3 -- yyyy/MM/dd HH:mm:ss
     *                   dateFormat = 4 -- yyyy年MM月dd日 HH时mm分ss秒
     * @return
     */
    public static String rollSecond(Date dateTime, int sec, int dateFormat) {
        Date d = rollSecond(dateTime, sec);
        return dateTimeFormat(dateFormat).format(d);
    }

    /**
     * 获取指定时间之前或之后多少秒的时间字符串
     *
     * @param dateTime   待加、减时间
     * @param sec        加、减秒数
     * @return
     */
    public static Date rollSecond(Date dateTime, int sec) {
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.SECOND, sec);
        return c.getTime();
    }

    /**
     * 获取指定时间之前或之后多少分钟的时间字符串
     *
     * @param dateTime   待加、减时间
     * @param min        加、减分钟数
     * @param dateFormat dateFormat = 1 -- yyyyMMddHHmmss
     *                   dateFormat = 2 -- yyyy-MM-dd HH:mm:ss
     *                   dateFormat = 3 -- yyyy/MM/dd HH:mm:ss
     *                   dateFormat = 4 -- yyyy年MM月dd日 HH时mm分ss秒
     * @return
     */
    public static String rollMinute(Date dateTime, int min, int dateFormat) {
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.MINUTE, min);
        Date d = c.getTime();
        return dateTimeFormat(dateFormat).format(d);
    }

    /**
     * 获取指定时间之前或之后多少分钟的时间字符串
     *
     * @param dateTime   待加、减时间
     * @param min        加、减分钟数
     * @return
     */
    public static Date rollMinute(Date dateTime, int min) {
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.MINUTE, min);
        return c.getTime();
    }

    /**
     * 获取指定时间之前或之后多少天的时间字符串
     *
     * @param dateTime   待加、减天数
     * @param day        加、减天数
     * @param dateFormat dateFormat = 1 -- yyyyMMddHHmmss
     *                   dateFormat = 2 -- yyyy-MM-dd HH:mm:ss
     *                   dateFormat = 3 -- yyyy/MM/dd HH:mm:ss
     *                   dateFormat = 4 -- yyyy年MM月dd日 HH时mm分ss秒
     * @return
     */
    public static String rollDateTimeDay(Date dateTime, int day, int dateFormat) {
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.DAY_OF_MONTH, day);
        Date d = c.getTime();
        return dateTimeFormat(dateFormat).format(d);
    }

    /**
     * 获取指定时间之前或之后多少天的时间
     *
     * @param dateTime 待加、减天数
     * @param day      加、减天数
     */
    public static Date rollDateTimeDay(Date dateTime, int day) {
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.DAY_OF_MONTH, day);
        Date d = c.getTime();
        return d;
    }

    /**
     * 获得指定日期的格式
     *
     * @param date
     * @param dateFormat
     * @return
     */
    public static String getAppointDate(Date date, String dateFormat) {
        SimpleDateFormat format = new SimpleDateFormat(dateFormat);
        return format.format(date);
    }

    /**
     * 获取当前年
     *
     * @return
     */
    public static String getYear() {
        DateFormat format = new SimpleDateFormat("yyyy");
        return format.format(new Date());
    }

    public static String getYear(Date date) {
        DateFormat format = new SimpleDateFormat("yyyy");
        return format.format(date);
    }

    /**
     * 获取当前月
     *
     * @return
     */
    public static String getMonth() {
        DateFormat format = new SimpleDateFormat("MM");
        return format.format(new Date());
    }

    public static String getMonth(Date date) {
        DateFormat format = new SimpleDateFormat("MM");
        return format.format(date);
    }

    /**
     * 获取今天几号
     *
     * @return
     */
    public static String getDay() {
        DateFormat format = new SimpleDateFormat("dd");
        return format.format(new Date());
    }

    public static String getDay(Date date) {
        DateFormat format = new SimpleDateFormat("dd");
        return format.format(date);
    }

    /**
     * 获取当前时间，格式：HH:mm:ss
     *
     * @return
     */
    public static String getTime() {
        DateFormat format = new SimpleDateFormat("HH:mm:ss");
        return format.format(new Date());
    }

    /**
     * 获取当前时间
     *
     * @return
     */
    public static int getCurTime() {
        DateFormat format = new SimpleDateFormat("HHmmss");
        String curTime = format.format(new Date());
        return Integer.parseInt(curTime);
    }

    /**
     * 获取今天是星期几
     *
     * @return
     */
    public static String getDayOfWeek() {
        DateFormat format = new SimpleDateFormat("EEEE");
        return format.format(new Date());
    }

    /**
     * 获得指定日期的间隔天数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int getIntervalDays(Date startDate, Date endDate) {
        return getIntervalDays(dateToCal(startDate), dateToCal(endDate));
    }

    /**
     * 获得指定日期的数值
     *
     * @param date
     * @return
     */
    public static GregorianCalendar dateToCal(Date date) {
        return new GregorianCalendar(
                Integer.parseInt(getAppointDate(date, "yyyy")),
                Integer.parseInt(getAppointDate(date, "MM")) - 1,
                Integer.parseInt(getAppointDate(date, "dd")),
                Integer.parseInt(getAppointDate(date, "HH")),
                Integer.parseInt(getAppointDate(date, "mm")),
                Integer.parseInt(getAppointDate(date, "ss")));
    }

    /**
     * 得到时间间隔天数
     *
     * @param g1 GregorianCalendar
     * @param g2 GregorianCalendar
     * @return int
     */
    public static int getIntervalDays(GregorianCalendar g1, GregorianCalendar g2) {
        int elapsed = 0;
        GregorianCalendar gc1;
        GregorianCalendar gc2;
        if (g2.after(g1)) {
            gc2 = (GregorianCalendar) g2.clone();
            gc1 = (GregorianCalendar) g1.clone();
        } else {
            gc2 = (GregorianCalendar) g1.clone();
            gc1 = (GregorianCalendar) g2.clone();
        }
        gc1.clear(Calendar.MILLISECOND);
        gc1.clear(Calendar.SECOND);
        gc1.clear(Calendar.MINUTE);
        gc1.clear(Calendar.HOUR_OF_DAY);
        gc1.clear(Calendar.HOUR);
        gc1.clear(Calendar.AM_PM);

        gc2.clear(Calendar.MILLISECOND);
        gc2.clear(Calendar.SECOND);
        gc2.clear(Calendar.MINUTE);
        gc2.clear(Calendar.HOUR_OF_DAY);
        gc2.clear(Calendar.HOUR);
        gc2.clear(Calendar.AM_PM);

        while (gc1.before(gc2)) {
            gc1.add(Calendar.DAY_OF_MONTH, 1);
            elapsed++;
        }
        return elapsed;
    }

    /**
     * 判断传入字符串是否是日期
     *
     * @param date       年月日
     * @param dateFormat dateFormat = 1 -- yyyyMMdd
     *                   dateFormat = 2 -- yyyy-MM-dd
     *                   dateFormat = 3 -- yyyy/MM/dd
     *                   dateFormat = 4 -- yyyy年MM月dd日
     * @return
     */
    public static boolean isDate(String date, int dateFormat) {
        try {
            Date date1 = string2date(date, dateFormat);
            String p = date2string(date1, dateFormat);
            if (p.equals(date)) {
                return true;
            }
        } catch (ParseException e) {
        }
        return false;
    }


    /**
     * 计算两个日期相差的毫秒值
     * @param startDate
     * @param endDate
     * @return
     */
    public static  int calLastedTime(Date startDate,Date endDate) {
        long a = endDate.getTime();
        long b = startDate.getTime();
        int c = (int) (a - b);
        return c;
    }

    /**
     * local时间转换成UTC时间
     * @param localDate
     * @return
     */
    public static Date localToUTC(Date localDate) {
        long localTimeInMillis=localDate.getTime();
        /** long时间转换成Calendar */
        Calendar calendar= Calendar.getInstance();
        calendar.setTimeInMillis(localTimeInMillis);
        /** 取得时间偏移量 */
        int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
        /** 取得夏令时差 */
        int dstOffset = calendar.get(Calendar.DST_OFFSET);
        /** 从本地时间里扣除这些差量，即可以取得UTC时间*/
        calendar.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        /** 取得的时间就是UTC标准时间 */
        Date utcDate=new Date(calendar.getTimeInMillis());
        return utcDate;
    }

    /**
     * local时间转换成UTC时间
     * @param localDate
     * @return
     */
    public static String getLocalToUTCString(Date localDate) {
        long localTimeInMillis=localDate.getTime();
        /** long时间转换成Calendar */
        Calendar calendar= Calendar.getInstance();
        calendar.setTimeInMillis(localTimeInMillis);
        /** 取得时间偏移量 */
        int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
        /** 取得夏令时差 */
        int dstOffset = calendar.get(Calendar.DST_OFFSET);
        /** 从本地时间里扣除这些差量，即可以取得UTC时间*/
        calendar.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        /** 取得的时间就是UTC标准时间 */
        Date utcDate=new Date(calendar.getTimeInMillis());
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        return df.format(utcDate);
    }

    /**
     * local时间转换成UTC时间
     * @param localDate
     * @return
     */
    public static Date getLocalToUTC(Date localDate) {
        long localTimeInMillis=localDate.getTime();
        /** long时间转换成Calendar */
        Calendar calendar= Calendar.getInstance();
        calendar.setTimeInMillis(localTimeInMillis);
        /** 取得时间偏移量 */
        int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
        /** 取得夏令时差 */
        int dstOffset = calendar.get(Calendar.DST_OFFSET);
        /** 从本地时间里扣除这些差量，即可以取得UTC时间*/
        calendar.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        /** 取得的时间就是UTC标准时间 */
        Date utcDate=new Date(calendar.getTimeInMillis());
        return utcDate;
    }

    public static Date isoToDate(String isoDate,String timeFormat) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(timeFormat);
        ZonedDateTime zonedDateTime = ZonedDateTime.parse(isoDate, dateTimeFormatter);
        ZonedDateTime local = zonedDateTime.withZoneSameInstant(ZoneId.systemDefault());
        return Date.from(local.toInstant());
    }

    public static String getIsoDate(Date date,String timeFormat) {
        ZonedDateTime zonedDateTime = Instant.ofEpochMilli(date.getTime())
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime().atZone(ZoneId.systemDefault());
        DateTimeFormatter isoFormatter = DateTimeFormatter.ofPattern(timeFormat);
        return zonedDateTime.format(isoFormatter);
    }
    /**
     * 日期比较
     *
     * @param time1      起始日期
     * @param time2      结束日期
     * @param dateFormat dateFormat = 1 -- yyyyMMdd
     *                   dateFormat = 2 -- yyyy-MM-dd
     *                   dateFormat = 3 -- yyyy/MM/dd
     *                   dateFormat = 4 -- yyyy年MM月dd日
     *                   dateFormat = 5 -- yyyy-MM-dd HH:mm:ss
     * @throws ParseException
     * @return 起始日期小于结束日期返回true，否则返回false
     */
    public static boolean isBeforeDate(Date time1, Date time2) throws ParseException {
        return time1.before(time2);
    }

    /**
     * 秒转时分秒
     * @param seconds
     * @return
     */
    public static String convertSecondsToHMmSs(long seconds) {
        long s = seconds % 60;
        long m = (seconds / 60) % 60;
        long h = (seconds / (60 * 60)) % 24;
        return String.format("%d:%02d:%02d", h,m,s);
    }
}